package net.sh.dpinfrastructure.support.global;

import org.apache.commons.lang3.StringUtils;

import com.google.common.collect.Sets;

import net.sh.dpinfrastructure.db.DPSystemFields;
import net.sh.dpinfrastructure.db.DPWriteResult;
import net.sh.dpinfrastructure.exception.DPException;
import net.sh.dpinfrastructure.mongo.DPCollection;
import net.sh.dpinfrastructure.mongo.DPDocument;

/**
 * 
 * 使用mongo来实现表id的自增，每个代表表名的字段的id都表示为当前该表最大id
 * 
 * @version 1.0
 * @since JDK1.7
 * @author Lancer
 * @company 上海朝阳永续信息技术有限公司
 * @copyright (c) 2017 SunTime Co'Ltd Inc. All rights reserved.
 * @date 2017年2月9日 下午7:46:33
 */
public class DPIDGenerateServiceUseMongo implements DPIDGenerateService {
    
    /**
     * 用来保存表id的mongo表
     */
    private DPCollection collection; 
    
    public DPIDGenerateServiceUseMongo(DPCollection collection) {
        this.collection = collection;
    }
    
    public DPCollection getCollection() {
        return collection;
    }

    /**
     * {@inheritDoc}<br>
     * @see #getIncrementId(String, long) 
     */
    @Override
    public long getIncrementId(String tableName) {
        return this.getIncrementId(tableName, 1);
    }

    /**
     * {@inheritDoc}<br>
     * 每次执行该方法后对应表id都递增 <i>step</i>，使用乐观锁来控制事务，并在该表上对字段<i>table_name</i>做唯一性约束
     */
    @Override
    public long getIncrementId(String tableName, long step) {

        if (StringUtils.isBlank(tableName)) {
            throw new IllegalArgumentException("empty table name");
        }
        
        if (step <= 1) {
            throw new IllegalArgumentException("step is less than 1");
        }
        
        DPDocument document = collection.findDocument(new DPDocument("table_name", tableName), Sets.newHashSet("current_max_id", DPSystemFields.VERSION));
        long id;
        if (document == null) {
            id = 1L;
            try {
                collection.insert(new DPDocument("table_name", tableName).append("current_max_id", id).append(DPSystemFields.VERSION, 1L));
            } catch (Exception e) {
                throw new DPException("get id failed", e);
            }
        } else {
            long version = document.getLong(DPSystemFields.VERSION);
            id =  document.getLong("current_max_id") + step;
            DPWriteResult writeResult = collection.update(new DPDocument("table_name", tableName).append(DPSystemFields.VERSION, version), 
                    new DPDocument("$set", new DPDocument("current_max_id", id).append(DPSystemFields.VERSION, version + 1)), false, false);
            if (writeResult.getMatchedCount() == 0) { // 请求（version）过期则重新发起请求
                throw new DPException("get id failed due to concurrence");
            }
        }
        return id;
    }
    
    public void setCollection(DPCollection collection) {
        this.collection = collection;
    }
}
